/**
 * Copyright 2010 Victor Egea Hernando
 *
 * RockScript is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * RockScript is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with RockScript.  If not, see <http://www.gnu.org/licenses/>.
 */
#ifndef PJIT_BUFFER_H_
#define PJIT_BUFFER_H_

#include "pjit.h"
#include "pjit_block.h"
#include "targets/pjit_codegen.h"

#include <list>

namespace pjit{

/**
 * Conventions:
 * 	(01) You must push the arguments backwards to call a
 * 	     function, push after push, until you call it, ie:
 *
 * 	      void function( ctype &x1, ctype &x2 );
 * 	      ctype o1, o2; function( o1, o2 );
 * 	      ...
 * 	      lir_pushargptr( &o2 );
 * 	      lir_pushargptr( &o1 );
 * 	      lir_call( reinterpret_cast<void*>( &function ) );
 */

class PAPER_API pjit_buffer{

public:
	// OPERANDS
	enum __lir_op{
		loadi32,loadr32,loadi32p,loadr32p,loadptr,
		label,cjmp,jmp,
		pusharg32,pushargptr,pushargregref,
		call,ret,
		addi,subi,muli,divi,
		addr,subr,mulr,divr,sqrtr
	};
	// PJIT LIR UNION
	typedef union __lir_val{
		uint32  vuint32;
		int32   vint32;
		real32  vreal32;
		int32  *pint32;
		real32 *preal32;
		void   *pvoid;
	};
	// PJIT IR
	typedef struct __lir_quad{
		__lir_op  op;
		__lir_val rs1;
		uint32    rs2;
		uint32    rt;
	};
	// ITERATOR
	typedef std::list<__lir_quad>::iterator quad_it;

protected:
	// BUFFER ATTRIBUTES
	uint32 _nlabel;
	quad_it _quad_it;
	pjit_codegen *_codegen;
	std::list<__lir_quad> _lir;

public:
	// CONSTRUCTOR & DESTRUCTOR
	pjit_buffer( void );
	virtual ~pjit_buffer();
	// MAIN INTERFACE (LIR)
	pjit_buffer &lir_loadi32      ( int32 val, uint32 rt );
	pjit_buffer &lir_loadr32      ( real32 val, uint32 rt );
	pjit_buffer &lir_loadi32p     ( int32 *valp, uint32 rt );
	pjit_buffer &lir_loadr32p     ( real32 *valp, uint32 rt );
	pjit_buffer &lir_loadptr      ( void *valp, uint32 rt );
	pjit_buffer &lir_label        ( uint32 lab );
	pjit_buffer &lir_cjmp         ( uint32 lab );
	pjit_buffer &lir_jmp          ( uint32 lab );
	pjit_buffer &lir_pusharg32    ( uint32 rs1 );
	pjit_buffer &lir_pushargptr   ( void *dir );
	pjit_buffer &lir_pushargregref( uint32 rs1 );
	pjit_buffer &lir_call         ( void *dir );
	pjit_buffer &lir_ret          ( void );
	pjit_buffer &lir_addi         ( uint32 rs1, uint32 rs2, uint32 rt );
	pjit_buffer &lir_subi         ( uint32 rs1, uint32 rs2, uint32 rt );
	pjit_buffer &lir_muli         ( uint32 rs1, uint32 rs2, uint32 rt );
	pjit_buffer &lir_divi         ( uint32 rs1, uint32 rs2, uint32 rt );
	pjit_buffer &lir_addr         ( uint32 rs1, uint32 rs2, uint32 rt );
	pjit_buffer &lir_subr         ( uint32 rs1, uint32 rs2, uint32 rt );
	pjit_buffer &lir_mulr         ( uint32 rs1, uint32 rs2, uint32 rt );
	pjit_buffer &lir_divr         ( uint32 rs1, uint32 rs2, uint32 rt );
	pjit_buffer &lir_sqrtr        ( uint32 rs1, uint32 rt );
	// MAIN INTERFACE (OTHERS)
	uint32 next_label( void );
	uint32 size( void ) const;
	std::list<__lir_quad>::iterator end_quad( void );
	std::list<__lir_quad>::iterator next_quad( void );
	std::list<__lir_quad>::iterator begin_quad( void );
	// MAIN INTERFACE (COMPILE)
	pjit_buffer &compile( pjit_block &block );
};

}; // namespace pjit

#endif // PJIT_BUFFER_H_
